嗯?開機就收到明天是「特殊工作日」的通知,但是這兩天都要辛勤工作,沒差...出門寫作業去。
因為要用功,所以就到插座多的咖啡店。上班時間咖啡店人都不多,沒人跟我搶插座,很好...今天要完成一半的測試,同時覆蓋率要80%以上...開始,然後各種鬼打牆XD
原來的程式只是從範例修改的,寫得有點隨便阿,重點是有點難測試,考慮了一下幾個函數需要使用的參數,把他整理到consturctor函數裡面,不是全部都用到的,就改成各自的參數,然後原本直接呼叫的callback,也改成參數傳入,總算可以見人...Statement, Branch, Func, Line都超過80%,沒跑到的大致上都是catch,這樣應該可以。
結果這樣搞著就傍晚了XD,先來煮個麵吃~~
晚上還是看一下pptx viewer,畢竟昨天沒進度。之前處理的是副檔名為.rels
的xml檔,今天來處理其他的xml檔。用原本的處理方式,轉出來的json會長這樣(docProps/core.xml
):
{
"type": "DOCUMENT_NODE",
"value": "",
"children": [
{
"type": "ELEMENT_NODE",
"tagName": "cp:coreProperties",
"attributes": {
"xmlns:cp": "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
"xmlns:dc": "http://purl.org/dc/elements/1.1/",
"xmlns:dcterms": "http://purl.org/dc/terms/",
"xmlns:dcmitype": "http://purl.org/dc/dcmitype/",
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance"
},
"value": "",
"children": [
{
"type": "ELEMENT_NODE",
"tagName": "dc:title",
"attributes": {},
"value": "Colour Pencils PowerPoint Template",
"children": []
},
{
"type": "ELEMENT_NODE",
"tagName": "dc:creator",
"attributes": {},
"value": "Presentation Magazine",
"children": []
},
{
"type": "ELEMENT_NODE",
"tagName": "cp:lastModifiedBy",
"attributes": {},
"value": "Hsu Ping Feng",
"children": []
},
{
"type": "ELEMENT_NODE",
"tagName": "cp:revision",
"attributes": {},
"value": "58",
"children": []
},
{
"type": "ELEMENT_NODE",
"tagName": "dcterms:created",
"attributes": {
"xsi:type": "dcterms:W3CDTF"
},
"value": "2009-11-03T13:35:13Z",
"children": []
},
{
"type": "ELEMENT_NODE",
"tagName": "dcterms:modified",
"attributes": {
"xsi:type": "dcterms:W3CDTF"
},
"value": "2016-10-14T08:03:12Z",
"children": []
}
]
}
]
}
其實就是用一個簡單的樹狀結構保留原本的xml結構跟資訊,這樣資訊雖然完整,但是看起來很不直覺。稍微調整一下讓他用屬性及child node的tag name當作物件的property,會比較容易理解。先改一下程式:
<!DOCTYPE html>
<html>
<head>
<title>file reader</title>
<style>
.dropable {
width: 99%;
height: 100px;
background-color: #369;
color: white;
border: solid 3px gray;
border-radius: 5px;
padding: 5px 5px 5px 5px;
}
.message {
width: 99%;
background-color: #ddd;
border: solid 1px gray;
border-radius: 5px;
overflow: auto;
}
.preview {
font-size: 10px;
}
</style>
</head>
<body>
<div id="target" class="dropable">
<select id="encoding">
<option value="utf-8">utf-8</option>
<option value="big5">big5</option>
<option value="gb2312">gb2312</option>
<option value="shift-jis">shift-jis</option>
</select>
<input type="file" id="file" />
<div id="console"></div>
</div>
<div id="panel" class="message"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pako/1.0.11/pako_inflate.min.js"></script>
<script src="lib/zipfs.js"></script>
<script src="node_modules/xmlrun/index.js"></script>
<script>
var _target = document.getElementById('target');
var _message = document.getElementById('panel');
var _file = document.getElementById('file');
_file.onchange = function(e) {
clearlog();
if (this.files.length > 0) {
var reader = new FileReader();
reader.onload = (e) => {
var buffer = e.target.result;
log('file size: ' + buffer.byteLength);
let encoding = document.getElementById('encoding').value;
let start = new Date().getTime();
zipfs(buffer, pako.inflateRaw, encoding, (err, files) => {
if (!!err) return console.log(err);
log(`in callback: ${files.length} files extracted.`);
log(`${(new Date().getTime()-start)} ms`);
let str = '<table border="1" cellspacing="0" cellpadding="5" width="99%"><tr><th>file name</th><th>buffer length</th><th>last modified date</th><th>last modified time</th><th>compressed size</th><th>uncompressed size</th></tr>';
files.forEach(file => {
str += `<tr><td>${file.file_name}</td><td>${file.content.length}</td><td>${zipfs.formatMSDOSDate(file.last_modified_date)}</td><td>${zipfs.formatMSDOSTime(file.last_modified_time)}</td><td>${file.compressed_size}</td><td>${file.uncompressed_size}</td></tr>`;
str += `<tr><td colspan="6" class="preview" style="overflow-x:hidden">`;
if (checkExt(file.file_name, '.rels')) {
let runner = xmlnode(zipfs.uintToString(file.content));
runner.setRunner('default', function(target) {
if(!!target.child) {
return target.child.reduce((acc, cur) => {
Object.assign(acc, cur.run());
return acc;
}, {})
}
else return {};
});
runner.setRunner('Relationship', target => {
let result = {};
result[target.attr['Id']] = target.attr['Target'];
result[target.attr['Target']] = target.attr['Id'];
return result;
});
let obj = runner.run();
str += `<pre>${JSON.stringify(obj, null, 2)}</pre>`;
}
if (checkExt(file.file_name, '.xml')) {
let runner = xmlnode(zipfs.uintToString(file.content));
runner.setRunner('default', function(target) {
/*let result = {
type: xmlnode.utils.getNodeTypeDesc(target.type),
tagName: target.tag,
attributes: target.attr,
value: target.val,
children: []
}
if(!!target.child) {
result.children = target.child.reduce((acc, cur) => {
acc.push(cur.run());
return acc;
}, []);
}
return result;*/
let result = {};
if(!!target.attr) {
result = Object.keys(target.attr).reduce((pre, cur) => {
pre[cur] = target.attr[cur];
return pre;
}, {});
}
if(!!target.val) result._value = target.val;
if(!!target.child && Array.isArray(target.child) && target.child.length > 0) {
target.child.forEach(c => {
if(!result[c.tag]) {
result[c.tag] = c.run();
} else {
if(Array.isArray(result[c.tag])) {
result[c.tag].push(c.run());
} else {
let _t = result[c.tag];
result[c.tag] = [];
result[c.tag].push(_t);
result[c.tag].push(c.run());
}
}
});
}
return result;
});
let obj = runner.run();
str += `<pre>${JSON.stringify(obj, null, 2)}</pre>`;
}
if (checkExt(file.file_name, '.jpeg') || checkExt(file.file_name, '.jpg')) {
let im = new Image();
im.src = `data:image/jpeg;base64,${zipfs.arrayBufferToBase64(file.content)}`;
if(im.width > 1024) {
str += `<img width="1024px" src="data:image/jpeg;base64,${zipfs.arrayBufferToBase64(file.content)}">`;
} else {
str += `<img src="data:image/jpeg;base64,${zipfs.arrayBufferToBase64(file.content)}">`;
}
}
if (checkExt(file.file_name, '.png')) {
let im = new Image();
im.src = `data:image/png;base64,${zipfs.arrayBufferToBase64(file.content)}`;
if(im.width > 1024) {
str += `<img width="1024px" src="data:image/png;base64,${zipfs.arrayBufferToBase64(file.content)}">`;
} else {
str += `<img src="data:image/png;base64,${zipfs.arrayBufferToBase64(file.content)}">`;
}
}
if (checkExt(file.file_name, '.mp3')) {
str += '<audio controls type="audio/mpeg" src="data:audio/mp3;base64,' +
zipfs.arrayBufferToBase64(file.content) + '">';
}
str += '</td></tr>';
});
str += '</table>';
document.getElementById('panel').innerHTML = str;
});
};
reader.readAsArrayBuffer(this.files[0]);
}
function checkExt(name, ext) {
return name.lastIndexOf(ext) === name.length - ext.length;
}
function log(msg) {
document.getElementById('console').innerHTML += `<br />${msg}`;
}
function clearlog() {
document.getElementById('console').innerHTML = '';
}
}
</script>
</body>
</html>
然後core.xml
會變成這樣的json:
{
"cp:coreProperties": {
"xmlns:cp": "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
"xmlns:dc": "http://purl.org/dc/elements/1.1/",
"xmlns:dcterms": "http://purl.org/dc/terms/",
"xmlns:dcmitype": "http://purl.org/dc/dcmitype/",
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
"dc:title": {
"_value": "Colour Pencils PowerPoint Template"
},
"dc:creator": {
"_value": "Presentation Magazine"
},
"cp:lastModifiedBy": {
"_value": "Hsu Ping Feng"
},
"cp:revision": {
"_value": "58"
},
"dcterms:created": {
"xsi:type": "dcterms:W3CDTF",
"_value": "2009-11-03T13:35:13Z"
},
"dcterms:modified": {
"xsi:type": "dcterms:W3CDTF",
"_value": "2016-10-14T08:03:12Z"
}
}
}
這樣就比較好讀一點了。如果有重複的tag name,底下的property會改成陣列,例如docProps/app.xml
底下的vt:variant
:
{
"Properties": {
"xmlns": "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",
"xmlns:vt": "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes",
"TotalTime": {
"_value": "1986"
},
"Words": {
"_value": "471"
},
"Application": {
"_value": "Microsoft Macintosh PowerPoint"
},
"PresentationFormat": {
"_value": "如螢幕大小 (4:3)"
},
"Paragraphs": {
"_value": "106"
},
"Slides": {
"_value": "8"
},
"Notes": {
"_value": "7"
},
"HiddenSlides": {
"_value": "0"
},
"MMClips": {
"_value": "0"
},
"ScaleCrop": {
"_value": "false"
},
"HeadingPairs": {
"vt:vector": {
"size": "6",
"baseType": "variant",
"vt:variant": [
{
"vt:lpstr": {
"_value": "使用字型"
}
},
{
"vt:i4": {
"_value": "3"
}
},
{
"vt:lpstr": {
"_value": "佈景主題"
}
},
{
"vt:i4": {
"_value": "2"
}
},
{
"vt:lpstr": {
"_value": "投影片標題"
}
},
{
"vt:i4": {
"_value": "8"
}
}
]
}
},
...
}
...
}
今天比較累,就先這樣,不然沒時間打ESO了....